// ------------------------------------------------------------------------------------------------
// File   : DX9DOF.cpp
// Date   : 2011-05-19
// Author : Weng xiao yi
// Descr. : Create an Post process Depth of Field Effect 
//
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// HEADERS
// ------------------------------------------------------------------------------------------------
#include <engine_stdafx.h>
// ------------------------------------------------------------------------------------------------
// IMPLEMENTATION
// ------------------------------------------------------------------------------------------------
DX9AE_DOF::DX9AE_DOF()
: DX9AfterEffect()
{
	SetAllResourceNull();
}

DX9AE_DOF::~DX9AE_DOF()
{
	Shutdown();
}

void DX9AE_DOF::SetAllResourceNull()
{
}

void DX9AE_DOF::ReInit()
{
	SetAllResourceNull();

}

void DX9AE_DOF::OnDeviceLost()
{
	Shutdown();

	DX9AfterEffect::OnDeviceLost();
}

void DX9AE_DOF::OnDeviceReset()
{
	DX9AfterEffect::OnDeviceReset();

	ReInit();
}

void DX9AE_DOF::Shutdown()
{

}

void DX9AE_DOF::Apply()
{	
	HRESULT hr;
#if 0
	// This array defines the blur pattern to be used in the 
	// post process pixel shaders.  It is two hexagons, one a single pixel 
	// out and the other two pixels out with close to "equal" spacing between 
	// the points in order to get the best blurring.
	static float TwelveKernelBase[12][2] =
	{
		{ 1.0f,  0.0f},
		{ 0.5f,  0.8660f},
		{-0.5f,  0.8660f},
		{-1.0f,  0.0f},
		{-0.5f, -0.8660f},
		{ 0.5f, -0.8660f},

		{ 1.5f,  0.8660f},
		{ 0.0f,  1.7320f},
		{-1.5f,  0.8660f},
		{-1.5f, -0.8660f},
		{ 0.0f, -1.7320f},
		{ 1.5f, -0.8660f},
	};

	VECTOR4FLOAT PSTwelveKernelArray[12];

	IHRRenderer* RI = GetHREngine()->GetRenderer();
	LPDIRECT3DDEVICE9 pD3DDev = (LPDIRECT3DDEVICE9)(RI->GetRealDevice());
	ICubeMaterial::MaterialList &Mat_list = ICubeMaterial::GetInstance().GetMaterialList();
	const ICubeMaterial::MaterialInfo &FogMaterial_info = Mat_list[ICubeMaterial::eMaterial_posteffect];

	GetSceneEffect()->StretchBackBufferToDecolor();


	GetCubeMaterialRenderer()->PushMaterial( FogMaterial_info.m_material, MM_Add );
	GetCubeMaterialRenderer()->ComputeMaterialPass();
	GetCubeMaterialRenderer()->OnePassPreRenderMaterial( 0 );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature;
	oVSFeature.stKey.ulShaderVer	 = 20;
	oVSFeature.stKey.ulEffectId      = AE_TYPE_DOF;
	oVSFeature.stKey.ulEffectSubType = AE_TYPE_DOF_TWO_KERNEL_HEXAGONS;
	DX9VertexShader* pVertexShader = DX9GetVertexShaderManager()->GetShader(&oVSFeature);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature;
	oPSFeature.stKey.ulShaderVer	  = 20;
	oPSFeature.stKey.ulEffectId      = AE_TYPE_DOF;
	oPSFeature.stKey.ulEffectSubType = AE_TYPE_DOF_TWO_KERNEL_HEXAGONS;
	DX9PixelShader* pPixelShader = DX9GetPixelShaderManager()->GetShader(&oPSFeature);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );


	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );
	pD3DDev->SetTexture( 1, GetSceneEffect()->GetBKDepthTexture() );

	VECTOR4FLOAT vScreenResolution;
	vScreenResolution.x = GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.y = GetHR3DConfig()->GetScreenHeight();
	vScreenResolution.z = 0.5f / GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.w = 0.5f / GetHR3DConfig()->GetScreenHeight();

	// upload constants
	if (pVertexShader->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );

	// Calculate the scale factor to convert the input array to screen space
	float fWidthMod = GetWorld().GetPostProcessData()->fDOFBlurValue / vScreenResolution.x ;
	float fHeightMod = GetWorld().GetPostProcessData()->fDOFBlurValue / vScreenResolution.y;

	// Scale the effect's kernel from pixel space to tex coord space
	// In pixel space 1 unit = one pixel and in tex coord 1 unit = width/height of texture
	for( int iEntry = 0; iEntry < 6; iEntry++ )
	{
		PSTwelveKernelArray[iEntry].x = TwelveKernelBase[iEntry][0] * fWidthMod;
		PSTwelveKernelArray[iEntry].y = TwelveKernelBase[iEntry][1] * fHeightMod;
	}

	if( pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_DOF_KERNELARRAY ) )
		pPixelShader->SetGlobalVectorArray( PS_GLOBAL_CONSTANT_DOF_KERNELARRAY, (VECTOR4FLOAT*)&PSTwelveKernelArray, 12 );


	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );


	pD3DDev->SetVertexShader(NULL);
	pD3DDev->SetPixelShader(NULL);
	pD3DDev->SetTexture( 0, NULL );
	pD3DDev->SetTexture( 1, NULL );

	GetCubeMaterialRenderer()->OnePassPostRenderMaterial( 0 );
	GetCubeMaterialRenderer()->PopMaterial();

#endif

	if( GetWorld().GetPostProcessData()->fDOFBlurValue == 0.0f )
		return;

	IHRRenderer* RI = GetHREngine()->GetRenderer();
	LPDIRECT3DDEVICE9 pD3DDev = (LPDIRECT3DDEVICE9)(RI->GetRealDevice());
	ICubeMaterial::MaterialList &Mat_list = ICubeMaterial::GetInstance().GetMaterialList();
	const ICubeMaterial::MaterialInfo &DOFMaterial_info = Mat_list[ICubeMaterial::eMaterial_posteffect];

	DX9AfterEffect *pDX9AfterEffect = DX9AfterEffectManager::GetInstance()->GetAfterEffect(AE_Bloom);
	DX9AE_Bloom *pBloomEffect = static_cast<DX9AE_Bloom*>(pDX9AfterEffect);
	if( !pBloomEffect )
		return;

	pD3DDev->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	pD3DDev->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	pD3DDev->SetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	pD3DDev->SetSamplerState( 1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	pD3DDev->SetSamplerState( 2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	pD3DDev->SetSamplerState( 2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );

	VECTOR4FLOAT vScreenResolution;
	vScreenResolution.x = GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.y = GetHR3DConfig()->GetScreenHeight();
	vScreenResolution.z = 0.5f / GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.w = 0.5f / GetHR3DConfig()->GetScreenHeight();

	VECTOR4FLOAT vBlurScreenResolution;
	vBlurScreenResolution.x = 1.0f / GetHR3DConfig()->GetScreenWidth();
	vBlurScreenResolution.y = 1.0f / GetHR3DConfig()->GetScreenHeight();
	vBlurScreenResolution.z = 1.0f / (GetHR3DConfig()->GetScreenWidth() / 2.0f);
	vBlurScreenResolution.w = 1.0f / (GetHR3DConfig()->GetScreenHeight() / 2.0f);


	VECTOR4FLOAT vBlurDirectionH, vBlurDirectionV;
	vBlurDirectionH.x = 1;
	vBlurDirectionH.y = 0;
	vBlurDirectionV.x = 0;
	vBlurDirectionV.y = 1;

	VECTOR4FLOAT vBlurWidth;
	vBlurWidth.x = GetWorld().GetPostProcessData()->fDOFBlurValue;


	GetSceneEffect()->StretchBackBufferToDecolor();


	LPDIRECT3DSURFACE9 pDefaultRT = NULL;
	LPDIRECT3DSURFACE9 pDefaultRTDepth = NULL;

	pD3DDev->GetRenderTarget( 0, &pDefaultRT );
	pD3DDev->GetDepthStencilSurface( &pDefaultRTDepth );
	DX9Verify(pDefaultRT);
	DX9Verify(pDefaultRTDepth);


	GetCubeMaterialRenderer()->PushMaterial( DOFMaterial_info.m_material, MM_Add );
	GetCubeMaterialRenderer()->ComputeMaterialPass();
	GetCubeMaterialRenderer()->OnePassPreRenderMaterial( 0 );

	///////////////////////////STEP 1 DOWNSAMPLE/////////////////////////
	pD3DDev->SetRenderTarget( 0, pBloomEffect->GetDownSampleSurface() );
	pD3DDev->SetDepthStencilSurface( NULL );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature1;
	oVSFeature1.stKey.ulShaderVer	  = 20;
	oVSFeature1.stKey.ulEffectId      = AE_TYPE_BLOOM_DOWNSAMPLE;
	oVSFeature1.stKey.ulEffectSubType = 0;
	DX9VertexShader* pVertexShader1 = DX9GetVertexShaderManager()->GetShader(&oVSFeature1);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature1;
	oPSFeature1.stKey.ulShaderVer	  = 20;
	oPSFeature1.stKey.ulEffectId      = AE_TYPE_BLOOM_DOWNSAMPLE;
	oPSFeature1.stKey.ulEffectSubType = 0;
	DX9PixelShader* pPixelShader1 = DX9GetPixelShaderManager()->GetShader(&oPSFeature1);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader1->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader1->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );

	// upload constants
	if (pVertexShader1->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader1->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	///////////////////////////STEP 2 Blur H/////////////////////////
	pD3DDev->SetRenderTarget( 0, pBloomEffect->GetBlurSampleSurface() );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature2;
	oVSFeature2.stKey.ulShaderVer	  = 20;
	oVSFeature2.stKey.ulEffectId      = AE_TYPE_BLOOM_BLUR;
	oVSFeature2.stKey.ulEffectSubType = 0;
	DX9VertexShader* pVertexShader2 = DX9GetVertexShaderManager()->GetShader(&oVSFeature2);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature2;
	oPSFeature2.stKey.ulShaderVer	  = 20;
	oPSFeature2.stKey.ulEffectId      = AE_TYPE_BLOOM_BLUR;
	oPSFeature2.stKey.ulEffectSubType = 0;
	DX9PixelShader* pPixelShader2 = DX9GetPixelShaderManager()->GetShader(&oPSFeature2);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader2->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader2->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, pBloomEffect->GetDownSampleTexture() );

	// upload constants
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURDIRECTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURDIRECTION, &vBlurDirectionH );
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURWIDTH))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURWIDTH, &vBlurWidth );

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	///////////////////////////STEP 3 Blur V/////////////////////////
	pD3DDev->SetRenderTarget( 0, pBloomEffect->GetDownSampleSurface() );

	pD3DDev->SetTexture( 0, pBloomEffect->GetBlurSampleTexture() );

	// upload constants
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURDIRECTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURDIRECTION, &vBlurDirectionV );

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	///////////////////////////STEP 4 COMBINE ALL/////////////////////////
	pD3DDev->SetRenderTarget( 0, pDefaultRT );
	pD3DDev->SetDepthStencilSurface( pDefaultRTDepth );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature3;
	oVSFeature3.stKey.ulShaderVer	  = 20;
	oVSFeature3.stKey.ulEffectId      = AE_TYPE_DOF;
	oVSFeature3.stKey.ulEffectSubType = AE_TYPE_DOF_COMBINE;
	DX9VertexShader* pVertexShader3 = DX9GetVertexShaderManager()->GetShader(&oVSFeature3);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature3;
	oPSFeature3.stKey.ulShaderVer	  = 20;
	oPSFeature3.stKey.ulEffectId      = AE_TYPE_DOF;
	oPSFeature3.stKey.ulEffectSubType = AE_TYPE_DOF_COMBINE;
	DX9PixelShader* pPixelShader3 = DX9GetPixelShaderManager()->GetShader(&oPSFeature3);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader3->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader3->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );
	pD3DDev->SetTexture( 1, GetSceneEffect()->GetBKDepthTexture() );
	pD3DDev->SetTexture( 2, pBloomEffect->GetDownSampleTexture() );

	if (pPixelShader3->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_SCREENRESOLUTION))
		pPixelShader3->SetGlobalVector( PS_GLOBAL_CONSTANT_SCREENRESOLUTION, &vBlurScreenResolution );
	if (pPixelShader3->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_DOF_RADIUSSCALE))
		pPixelShader3->SetGlobalFloat( PS_GLOBAL_CONSTANT_DOF_RADIUSSCALE, GetWorld().GetPostProcessData()->fDOFBlurValue );


	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	pD3DDev->SetVertexShader(NULL);
	pD3DDev->SetPixelShader(NULL);
	pD3DDev->SetTexture( 0, NULL );
	pD3DDev->SetTexture( 1, NULL );
	pD3DDev->SetTexture( 2, NULL );

	GetCubeMaterialRenderer()->OnePassPostRenderMaterial( 0 );
	GetCubeMaterialRenderer()->PopMaterial();

	RI->RestoreSamplerState(0);
	RI->RestoreSamplerState(1);
	RI->RestoreSamplerState(2);

	DX9_SAFE_RELEASE(pDefaultRT);
	DX9_SAFE_RELEASE(pDefaultRTDepth);

}
